package cn.lingyangwl.agile.pay.common.service.impl;

import cn.lingyangwl.agile.system.SystemApi;
import cn.lingyangwl.agile.system.model.rqrs.user.LoginUserDeleteReq;
import cn.lingyangwl.agile.system.model.rqrs.user.UserPageReq;
import cn.lingyangwl.agile.system.model.rqrs.user.UserResp;
import cn.lingyangwl.agile.model.enums.BoolEnum;
import cn.lingyangwl.agile.common.core.exception.enums.GlobalErrorEnum;
import cn.lingyangwl.agile.model.module.auth.LoginUser;
import cn.lingyangwl.agile.common.security.utils.SecurityUtils;
import cn.lingyangwl.agile.pay.common.assembly.MchInfoAssembly;
import cn.lingyangwl.agile.pay.common.constants.Cs;
import cn.lingyangwl.agile.pay.common.constants.MchCons;
import cn.lingyangwl.agile.pay.common.manager.MchAppManager;
import cn.lingyangwl.agile.pay.common.manager.MchPayPassageManager;
import cn.lingyangwl.agile.pay.common.manager.PayInterfaceConfigManager;
import cn.lingyangwl.agile.pay.common.manager.PayMqSender;
import cn.lingyangwl.agile.pay.common.mapper.MchInfoMapper;
import cn.lingyangwl.agile.pay.common.model.mq.ResetIsvMchAppInfoConfigMQ;
import cn.lingyangwl.agile.pay.common.service.MchInfoService;
import cn.lingyangwl.agile.pay.common.service.PayOrderService;
import cn.lingyangwl.agile.pay.model.entity.*;
import cn.lingyangwl.agile.pay.model.rqrs.MchInfoQL;
import cn.lingyangwl.agile.pay.model.rqrs.MchInfoRQ;
import cn.lingyangwl.agile.pay.model.rqrs.MchInfoRS;
import cn.lingyangwl.framework.core.page.PageModel;
import cn.lingyangwl.framework.core.page.TableSupport;
import cn.lingyangwl.framework.data.mate.annotations.FieldBindHandle;
import cn.lingyangwl.framework.mybatis.plus.utils.PageUtil;
import cn.lingyangwl.framework.tool.core.StringUtils;
import cn.lingyangwl.framework.tool.core.exception.Assert;
import cn.lingyangwl.framework.tool.core.exception.BizException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yitter.idgen.YitIdHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * <p>
 * 商户信息表 服务实现类
 * </p>
 *
 * @author shenguangyang
 */
@Service
public class MchInfoServiceImpl extends ServiceImpl<MchInfoMapper, MchInfo> implements MchInfoService {

    @Resource
    private MchAppManager mchAppManager;
    @Resource
    private MchPayPassageManager mchPayPassageManager;
    @Resource
    private PayInterfaceConfigManager payInterfaceConfigManager;
    @Resource
    private SystemApi systemApi;
    @Resource
    private MchInfoAssembly mchInfoAssembly;
    @Resource
    private PayOrderService payOrderService;
    @Resource
    private PayMqSender payMqSender;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveMch(MchInfoRQ req) {
        // 校验特邀商户信息
//        if (mchInfo.getType() == CS.MCH_TYPE_ISVSUB && StringUtils.isNotEmpty(mchInfo.getIsvNo())) {
//            // 当前服务商状态是否正确
//            IsvInfo isvInfo = isvInfoService.getById(mchInfo.getIsvNo());
//            if (isvInfo == null || isvInfo.getState() == CS.NO) {
//                throw new BizException("当前服务商不可用");
//            }
//        }

        // 插入商户基本信息
        MchInfo mchInfo = mchInfoAssembly.toMchInfoPO(req);
        mchInfo.setMchNo("M" + YitIdHelper.nextId());
        boolean saveResult = save(mchInfo);
        Assert.isTrue(saveResult, new BizException(GlobalErrorEnum.OPERATION_FAIL_CREATE));

        // 插入商户默认应用
        MchApp mchApp = MchApp.builder().mchNo(mchInfo.getMchNo())
                .appName("默认应用")
                .status(BoolEnum.TRUE.getCode()).createdBy(req.getLoginUserName())
                .build();
        saveResult = mchAppManager.save(mchApp);
        Assert.isTrue(saveResult, new BizException(GlobalErrorEnum.OPERATION_FAIL_CREATE));

        // 存入商户默认用户ID
        MchInfo updateRecord = new MchInfo();
        updateRecord.setMchNo(mchInfo.getMchNo());
        updateRecord.setCreatedBy(String.valueOf(SecurityUtils.getUserId()));
        updateRecord.setCreatedAt(new Date());
        saveResult = updateById(updateRecord);
        Assert.isTrue(saveResult, new BizException(GlobalErrorEnum.OPERATION_FAIL_CREATE));
    }

    /**
     * 删除商户
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<Long> removeByMchNo(String mchNo) {
        // 0.当前商户是否存在
        MchInfo mchInfo = getById(mchNo);
        if (mchInfo == null) {
            throw new BizException("该商户不存在");
        }

        // 1.查看当前商户是否存在交易数据
        long payCount = payOrderService.count(PayOrder.lqw().eq(PayOrder::getMchNo, mchNo));
        Assert.isTrue(payCount <= 0, new BizException("该商户已存在交易数据，不可删除"));

        // 2.删除当前商户配置的支付通道
        mchPayPassageManager.remove(MchPayPassage.lqw().eq(MchPayPassage::getMchNo, mchNo));

        // 3.删除当前商户支付接口配置参数
        List<String> appIdList = new ArrayList<>();
        mchAppManager.list(MchApp.lqw().eq(MchApp::getMchNo, mchNo)).forEach(item -> appIdList.add(item.getId()));

        if (CollectionUtils.isNotEmpty(appIdList)) {
            payInterfaceConfigManager.remove(PayInterfaceConfig.lqw()
                    .in(PayInterfaceConfig::getInfoId, appIdList)
                    .eq(PayInterfaceConfig::getInfoType, Cs.INFO_TYPE_MCH_APP)
            );
        }

        UserPageReq userPageReq = UserPageReq.builder()
//                .belongInfoId(mchNo)
                .build();
        List<UserResp> userList = systemApi.listUser(userPageReq);

        // 4.删除当前商户应用信息
        if (CollectionUtils.isNotEmpty(appIdList)) {
            mchAppManager.removeByIds(appIdList);
        }

        // 返回的用户id
        List<Long> userIdList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(userList)) {
            for (UserResp user : userList) {
                userIdList.add(user.getId());
            }
        }

        // 6. 删除当前商户
        boolean removeMchInfo = removeById(mchNo);
        if (!removeMchInfo) {
            throw new BizException("删除当前商户失败");
        }

        // 推送修改消息
        ResetIsvMchAppInfoConfigMQ mq = ResetIsvMchAppInfoConfigMQ
                .build(ResetIsvMchAppInfoConfigMQ.RESET_TYPE_MCH_INFO, null, mchNo, null);
        payMqSender.send(mq);
        return userIdList;
    }

    @Override
    @FieldBindHandle
    public MchInfoRS getMchInfoByMchNo(String mchNo) {
        MchInfo mchInfo = this.getById(mchNo);
        return mchInfoAssembly.toMchInfoResp(mchInfo);
    }

    @Override
    @FieldBindHandle
    public IPage<MchInfoRS> pageMch(MchInfoQL query) {
        PageModel pageModel = TableSupport.buildPageRequest();
        LambdaQueryWrapper<MchInfo> lqw = MchInfo.lgw()
                .eq(StringUtils.isNotEmpty(query.getMchNo()), MchInfo::getMchNo, query.getMchNo())
                .eq(StringUtils.isNotEmpty(query.getStatus()), MchInfo::getStatus, query.getStatus())
                .eq(StringUtils.isNotEmpty(query.getType()), MchInfo::getType, query.getType())
                .like(StringUtils.isNotEmpty(query.getMchName()), MchInfo::getMchName, query.getMchName())
                .orderByDesc(MchInfo::getCreatedAt);
        Page<MchInfo> page = this.page(new Page<>(pageModel.getPageNum(), pageModel.getPageSize()), lqw);
        return PageUtil.to(page, mchInfoAssembly::toMchInfoResp);
    }

    @Override
    public void updateMch(MchInfoRQ req) {
        MchInfo mchInfo = mchInfoAssembly.toMchInfoPO(req);
        LoginUser loginUser = SecurityUtils.getLoginUser();
        // 如果商户状态为禁用状态，清除该商户用户登录信息
        if (MchCons.Status.DISABLE.equals(req.getStatus())) {
            LoginUserDeleteReq loginUserDeleteReq = LoginUserDeleteReq.builder().belongInfoId(req.getMchNo()).build();
            systemApi.deleteLoginUser(loginUserDeleteReq);
        }

        // 更新商户信息
        if (!this.updateById(mchInfo)) {
            throw new BizException(GlobalErrorEnum.OPERATION_FAIL_UPDATE);
        }

        // 推送修改消息
        ResetIsvMchAppInfoConfigMQ mq = ResetIsvMchAppInfoConfigMQ
                .build(ResetIsvMchAppInfoConfigMQ.RESET_TYPE_MCH_INFO, null, mchInfo.getMchNo(), null);
        payMqSender.send(mq);
    }
}
